package org.aldar.bquest.entity.effect;

import org.aldar.bquest.entity.pool.TilesPool;
import org.aldar.bquest.logic.layout.ScreenContentManager;
import org.aldar.bquest.resources.ResourceManager;
import org.aldar.bquest.screens.MainBoardScreen;
import org.andengine.engine.Engine;
import org.andengine.entity.Entity;
import org.andengine.entity.IEntity;
import org.andengine.entity.modifier.*;
import org.andengine.entity.primitive.Rectangle;
import org.andengine.entity.sprite.Sprite;
import org.andengine.opengl.texture.region.ITextureRegion;
import org.andengine.opengl.texture.region.ITiledTextureRegion;
import org.andengine.util.math.MathUtils;
import org.andengine.util.modifier.IModifier;

import java.util.Random;

/**
 * User: Daria
 * Date: 8/27/14 6:02 PM
 */
public class ParticleUtil {

    private static final float DURATION_ROTATE_STAR_ON_ACTIVATE = 0.8f;

    public static void makeParticleCircle(final float duration, final float centerX, final float centerY, final int circleRadius, final float singleDuration, final int particlesCount, final int particleRadius, final ITextureRegion textureRegion) {
        makeParticleCircle(duration, centerX, centerY, circleRadius, singleDuration, particlesCount, particleRadius,
                textureRegion, MainBoardScreen.getInstanceEngine(), MainBoardScreen.getScm().getTestLayer());
    }

    public static void makeParticleSpiral(final float duration, final float centerX, final float centerY, final int maxRadius, final float singleDuration, final int particlesCount, final int particleRadius,
                                          final ITextureRegion textureRegion, final Engine engine, final Entity layerToAttach) {
        final Rectangle point = new Rectangle(centerX, centerY, 1, 1, engine.getVertexBufferObjectManager());
        layerToAttach.attachChild(point);
        point.setVisible(false);
        point.setAlpha(0f);
        point.registerEntityModifier(new DelayModifier(duration, new IEntityModifier.IEntityModifierListener() {
            @Override
            public void onModifierStarted(IModifier<IEntity> pModifier, IEntity pItem) {
                //To change body of implemented methods use File | Settings | File Templates.
            }

            @Override
            public void onModifierFinished(IModifier<IEntity> pModifier, IEntity pItem) {
                engine.runOnUpdateThread(new Runnable() {
                    @Override
                    public void run() {
                        point.detachSelf();
                    }
                });
            }
        }) {
            @Override
            protected void onManagedUpdate(float pSecondsElapsed, IEntity pEntity) {
                float percentage = getSecondsElapsed() / duration;
                float angle = (float) (Math.PI * duration * 2 * (-(1 - percentage) * (1 - percentage) + 1));
                //Log.i("jewel", "in particle Update! " + percentage);
                float currentRadius = percentage * percentage * maxRadius;
                final float pointX = (float) (currentRadius * Math.cos(angle) + centerX);
                final float pointY = (float) (currentRadius * Math.sin(angle) + centerY);
                point.setPosition(pointX, pointY);
                float alpha = 1;
                if (percentage > 0.8) {
                    alpha = 1 - (percentage - 0.5f) * 2;
                }
                new ParticleEmitter(particlesCount, particleRadius, singleDuration, pointX, pointY, 1 - percentage, textureRegion, engine, layerToAttach).start();
                super.onManagedUpdate(pSecondsElapsed, pEntity);    //To change body of overridden methods use File | Settings | File Templates.
            }
        });

    }

    public static void makeParticleCircle(final float duration, final float centerX, final float centerY, final int circleRadius, final float singleDuration, final int particlesCount, final int particleRadius,
                                          final ITextureRegion textureRegion, final Engine engine, final Entity layerToAttach) {
        final Rectangle point = new Rectangle(centerX, centerY, 1, 1, engine.getVertexBufferObjectManager());
        layerToAttach.attachChild(point);
        point.setVisible(false);
        point.setAlpha(0f);
        point.registerEntityModifier(new DelayModifier(duration, new IEntityModifier.IEntityModifierListener() {
            @Override
            public void onModifierStarted(IModifier<IEntity> pModifier, IEntity pItem) {
                //To change body of implemented methods use File | Settings | File Templates.
            }

            @Override
            public void onModifierFinished(IModifier<IEntity> pModifier, IEntity pItem) {
                engine.runOnUpdateThread(new Runnable() {
                    @Override
                    public void run() {
                        point.detachSelf();
                    }
                });
            }
        }) {
            @Override
            protected void onManagedUpdate(float pSecondsElapsed, IEntity pEntity) {
                float percentage = getSecondsElapsed() / duration;
                float angle = (float) (Math.PI * 3 * percentage);
                //Log.i("jewel", "in particle Update! " + percentage);

                final float pointX = (float) (circleRadius * Math.cos(angle) + centerX);
                final float pointY = (float) (circleRadius * Math.sin(angle) + centerY);
                point.setPosition(pointX, pointY);
                float alpha = 1;
                if (percentage > 0.5) {
                    alpha = 1 - (percentage - 0.5f) * 2;
                }
                new ParticleEmitter(particlesCount, particleRadius, singleDuration, pointX, pointY, 1 - percentage, textureRegion, engine, layerToAttach).start();
                super.onManagedUpdate(pSecondsElapsed, pEntity);    //To change body of overridden methods use File | Settings | File Templates.
            }
        });
    }

    public static void makeParticleCircleForTileMatch(float centerX, float centerY) {
        ParticleUtil.makeParticleCircle(0.5f,
                centerX,
                centerY,
                20,
                0.2f,
                2,
                20,
                ResourceManager.getInstance().getParticleRegion()
        );

    }

    public static void makeCrystalPath(float duration, float fromX, float fromY, float toX, float toY) {
        makeCrystalPath(duration, 1f, fromX, fromY, toX, toY);
    }

    public static void makeCrystalPath(float duration, float scale, float fromX, float fromY, float toX, float toY) {
        //new ParticleEmitter(10, 100, 1f, currentX, currentY, ResourceManager.getInstance().getParticleRegion()).start();
        //final TileSprite copyTile = TilesPool.getSpriteForCrystalTile(col, row);
        //ScreenContentManager.getScreenContentManager().getBonusLayer().attachChild(copyTile.getTile());
        float randomDelay = new Random().nextInt(20) * 0.01f;
        //copyTile.getTile().setScale(0.5f);
        final Entity moveEntity = new Entity();
        ScreenContentManager.getScreenContentManager().getBonusLayer().attachChild(moveEntity);
        final Sprite crystal = TilesPool.getEntityForTexture(ResourceManager.getInstance().getMagicTileTextureRegion());
        crystal.setScale(scale);
        moveEntity.attachChild(crystal);
        moveEntity.registerEntityModifier(new SequenceEntityModifier(new DelayModifier(randomDelay),
                new QuadraticBezierCurveMoveModifier(duration, fromX, fromY, (fromX + 50) / 2 + new Random().nextInt(200) - 100, (fromY + 50) / 2, toX, toY,
                        new IEntityModifier.IEntityModifierListener() {
                            @Override
                            public void onModifierStarted(IModifier<IEntity> pModifier, IEntity pItem) {
                            }

                            @Override
                            public void onModifierFinished(IModifier<IEntity> pModifier, IEntity pItem) {
                                MainBoardScreen.getInstanceEngine().runOnUpdateThread(new Runnable() {
                                    @Override
                                    public void run() {
                                        crystal.detachSelf();
                                        TilesPool.pushEntityToStack(crystal);
                                        moveEntity.detachSelf();
                                    }
                                });
                            }
                        }) {
                }));
    }

    public static void makeParticlePath(float fromX, float fromY, float toX, float toY, final ITextureRegion particleRegion) {
        //new ParticleEmitter(10, 100, 1f, currentX, currentY, ResourceManager.getInstance().getParticleRegion()).start();
        //final TileSprite copyTile = TilesPool.getSpriteForCrystalTile(col, row);
        //ScreenContentManager.getScreenContentManager().getBonusLayer().attachChild(copyTile.getTile());
        float randomDelay = new Random().nextInt(20) * 0.01f;
        //copyTile.getTile().setScale(0.5f);
        final Entity moveEntity = new Entity();
        ScreenContentManager.getScreenContentManager().getBonusLayer().attachChild(moveEntity);
        moveEntity.registerEntityModifier(new SequenceEntityModifier(new DelayModifier(randomDelay),
                new QuadraticBezierCurveMoveModifier(1f, fromX, fromY, (fromX + 50) / 2 + new Random().nextInt(200) - 100, (fromY + 50) / 2, toX, toY,
                        new IEntityModifier.IEntityModifierListener() {
                            @Override
                            public void onModifierStarted(IModifier<IEntity> pModifier, IEntity pItem) {
                            }

                            @Override
                            public void onModifierFinished(IModifier<IEntity> pModifier, IEntity pItem) {
                                MainBoardScreen.getInstanceEngine().runOnUpdateThread(new Runnable() {
                                    @Override
                                    public void run() {
                                        moveEntity.detachSelf();
                                    }
                                });
                            }
                        }) {

                    private int lastMillisEmitted;

                    @Override
                    protected void onManagedUpdate(float pSecondsElapsed, IEntity pEntity) {
                        float percentage = this.getSecondsElapsed() / this.getDuration() * 100;
                        int millis = (int) (this.getSecondsElapsed() * 1000);
                        if (millis > lastMillisEmitted + 100) {
                            new ParticleEmitter(3, (int) (105 - percentage), 0.5f, moveEntity.getX(), moveEntity.getY(),
                                    particleRegion).start();
                            lastMillisEmitted = millis;
                        }
                        super.onManagedUpdate(pSecondsElapsed, pEntity);
                    }
                }));
    }

    public static void makeCoinPath(float fromX, float fromY, float toX, float toY, int numberOfCoins, Entity layer) {
        for (int i = 0; i < numberOfCoins; i++) {
            final Sprite goldCoin = TilesPool.getEntityForTexture(ResourceManager.getInstance().getGoldCoinParticleRegion());
            goldCoin.detachSelf();
            layer.attachChild(goldCoin);
            float randomDelay = new Random().nextInt(20) * 0.01f;
            float randomDuration = 1f + new Random().nextInt(10) * 0.05f;
            goldCoin.registerEntityModifier(new SequenceEntityModifier(
                    new DelayModifier(randomDelay),
                    new ParallelEntityModifier(
                            new AlphaModifier(0.2f, 0, 1),
                            getCoinSpinningModifier(),
                            new QuadraticBezierCurveMoveModifier(randomDuration, fromX, fromY, fromX - 100 + new Random().nextInt(200), fromY + MathUtils.random(200, 300), toX, toY,
                                    new IEntityModifier.IEntityModifierListener() {
                                        @Override
                                        public void onModifierStarted(IModifier<IEntity> pModifier, IEntity pItem) {
                                            //To change body of implemented methods use File | Settings | File Templates.
                                        }

                                        @Override
                                        public void onModifierFinished(IModifier<IEntity> pModifier, IEntity pItem) {
                                            MainBoardScreen.getInstanceEngine().runOnUpdateThread(new Runnable() {
                                                @Override
                                                public void run() {
                                                    goldCoin.clearEntityModifiers();
                                                    goldCoin.detachSelf();
                                                    TilesPool.pushEntityToStack(goldCoin);
                                                }
                                            });
                                        }
                                    })
                    )

            ));
        }
    }

    private static IEntityModifier getCoinSpinningModifier() {
        return new LoopEntityModifier(
                new SequenceEntityModifier(
                        new ScaleAtModifier(0.1f, 0, 1, 1, 1, 0.5f, 0.5f),
                        new ScaleAtModifier(0.1f, 1, 0, 1, 1, 0.5f, 0.5f)
                )
        );
    }

    public static void performConcertNotes(float startX, float startY) {
        int iterations = 5;
        for (int i = 0; i < iterations; i++) {
            float delay = 1.0f + i * 0.25f;
            float newX = startX + 50 + MathUtils.random(30);
            float newY = startY + 40 + MathUtils.random(40);
            final Sprite randomNote = TilesPool.getEntityForTexture(ResourceManager.getInstance().getParticlesConcert().getTextureRegion(MathUtils.random(2)));
            randomNote.setPosition(startX, startY);
            MainBoardScreen.getScm().getBonusLayer().attachChild(randomNote);
            randomNote.setAlpha(0);
            randomNote.registerEntityModifier(new SequenceEntityModifier(
                    new DelayModifier(delay),
                    new ParallelEntityModifier(
                            new SequenceEntityModifier(
                                    new AlphaModifier(0.5f, 0, 1),
                                    new AlphaModifier(0.5f, 1, 0)
                            ),
                            new MoveModifier(1f, startX, startY, newX, newY, new IEntityModifier.IEntityModifierListener() {
                                @Override
                                public void onModifierStarted(IModifier<IEntity> pModifier, IEntity pItem) {
                                }

                                @Override
                                public void onModifierFinished(IModifier<IEntity> pModifier, IEntity pItem) {
                                    MainBoardScreen.getInstanceEngine().runOnUpdateThread(new Runnable() {
                                        @Override
                                        public void run() {
                                            randomNote.detachSelf();
                                            TilesPool.pushEntityToStack(randomNote);
                                        }
                                    });
                                }
                            })
                    )));
        }

    }

    public static void effectDisappearWithRandomSmoke(float x, float y) {
        effectDisappearWithSmoke(x, y, true);
    }

    public static void effectDisappearWithSmoke(float x, float y) {
        effectDisappearWithSmoke(x, y, false);
    }

    public static void effectDisappearWithSmoke(float x, float y, boolean randomSize) {
        int iterations = 3;
        int radius = 30;
        for (int i = 0; i < iterations; i++) {
            float delay = i * 0.1f;
            float angle = (float) (Math.PI * 2 * i / iterations);

            final float targetX = (float) (radius * Math.cos(angle) + x);
            final float targetY = (float) (radius * Math.sin(angle) + y);

            final Sprite randomNote = TilesPool.getEntityForTexture(ResourceManager.getInstance().getParticlesSmoke().getTextureRegion(i));
            randomNote.setPosition(x, y);
            MainBoardScreen.getScm().getBonusLayer().attachChild(randomNote);
            randomNote.setAlpha(0);
            if (randomSize) {
                float randomScale = 0.5f + 0.2f * MathUtils.random(0, 10);
                randomNote.setScale(randomScale);
            }
            randomNote.registerEntityModifier(new SequenceEntityModifier(
                    new DelayModifier(delay),
                    new ParallelEntityModifier(
                            new ScaleAtModifier(0.5f, 1.5f, 2f, 0.5f, 0.5f),
                            new SequenceEntityModifier(
                                    new AlphaModifier(0.1f, 0, 1),
                                    new AlphaModifier(0.4f, 1, 0)
                            ),
                            new MoveModifier(0.5f, x, y, targetX, targetY, new IEntityModifier.IEntityModifierListener() {
                                @Override
                                public void onModifierStarted(IModifier<IEntity> pModifier, IEntity pItem) {
                                }

                                @Override
                                public void onModifierFinished(IModifier<IEntity> pModifier, IEntity pItem) {
                                    MainBoardScreen.getInstanceEngine().runOnUpdateThread(new Runnable() {
                                        @Override
                                        public void run() {
                                            randomNote.detachSelf();
                                            TilesPool.pushEntityToStack(randomNote);
                                        }
                                    });
                                }
                            })
                    )));
        }
    }

    public static void effectFlames(float duration, float x, float y) {
        effectExplode(360, 40, 1f, duration, x, y, ResourceManager.getInstance().getParticlesFlame());
    }

    public static void effectSparks(float duration, float x, float y) {
        effectExplode(90, 20, 2f, duration, x, y, ResourceManager.getInstance().getParticlesSpark());
    }

    public static void effectGoldenStars(float duration, float x, float y) {
        effectExplode(90, 20, 2f, duration, x, y, ResourceManager.getInstance().getParticlesGoldenStars());
    }

    public static void effectExplode(float rotationAngle, float radius, float scale, float duration, float x, float y, ITiledTextureRegion textureRegion) {
        int iterations = 10;
        for (int i = 0; i < iterations; i++) {
            float delay = MathUtils.random(iterations) * 0.02f;
            float angle = (float) (Math.PI * 2 * MathUtils.random(iterations * 10) / (iterations * 10));

            final float targetX = (float) (radius * Math.cos(angle) + x);
            final float targetY = (float) (radius * Math.sin(angle) + y);

            final Sprite randomNote = TilesPool.getEntityForTexture(textureRegion.getTextureRegion(MathUtils.random(textureRegion.getTileCount())));
            randomNote.setPosition(x, y);
            randomNote.setScale(scale);
            MainBoardScreen.getScm().getBonusLayer().attachChild(randomNote);
            randomNote.registerEntityModifier(new SequenceEntityModifier(
                    new DelayModifier(delay),
                    new ParallelEntityModifier(
                            new SequenceEntityModifier(
                                    new AlphaModifier(duration * 0.2f, 0, 1),
                                    new DelayModifier(duration * 0.6f),
                                    new AlphaModifier(duration * 0.2f, 1, 0)
                            ),
                            new MoveModifier(duration, x, y, targetX, targetY),
                            new RotationModifier(duration, 0, rotationAngle * 2 * (MathUtils.random(1) - 0.5f), new IEntityModifier.IEntityModifierListener() {
                                @Override
                                public void onModifierStarted(IModifier<IEntity> pModifier, IEntity pItem) {
                                }

                                @Override
                                public void onModifierFinished(IModifier<IEntity> pModifier, IEntity pItem) {
                                    MainBoardScreen.getInstanceEngine().runOnUpdateThread(new Runnable() {
                                        @Override
                                        public void run() {
                                            randomNote.detachSelf();
                                            TilesPool.pushEntityToStack(randomNote);
                                        }
                                    });
                                }
                            })
                    )));
        }
    }

    public static void effectExtinguishFire(float x, float y) {
        int iterations = 3;
        int radius = 30;
        for (int i = 0; i < iterations; i++) {
            float delay = i * 0.1f;

            float newStartX = x - 25 + MathUtils.random(50);
            final float targetY = y + 25 + MathUtils.random(25);

            final Sprite randomNote = TilesPool.getEntityForTexture(ResourceManager.getInstance().getParticlesSmoke().getTextureRegion(i));
            randomNote.setPosition(x, y);
            MainBoardScreen.getScm().getBonusLayer().attachChild(randomNote);
            randomNote.setAlpha(0);
            randomNote.registerEntityModifier(new SequenceEntityModifier(
                    new DelayModifier(delay),
                    new ParallelEntityModifier(
                            new ScaleAtModifier(1.0f, 1.5f, 2f, 0.5f, 0.5f),
                            new SequenceEntityModifier(
                                    new AlphaModifier(0.2f, 0, 1),
                                    new AlphaModifier(0.8f, 1, 0)
                            ),
                            new MoveModifier(1.0f, newStartX, y, newStartX, targetY, new IEntityModifier.IEntityModifierListener() {
                                @Override
                                public void onModifierStarted(IModifier<IEntity> pModifier, IEntity pItem) {
                                }

                                @Override
                                public void onModifierFinished(IModifier<IEntity> pModifier, IEntity pItem) {
                                    MainBoardScreen.getInstanceEngine().runOnUpdateThread(new Runnable() {
                                        @Override
                                        public void run() {
                                            randomNote.detachSelf();
                                            TilesPool.pushEntityToStack(randomNote);
                                        }
                                    });
                                }
                            })
                    )));
        }
    }


    public static void showStarRotationEffect(float duration, float x, float y, Entity layer) {
        showStarRotationEffect(duration, 1f, x, y, layer);
    }

    public static void showStarRotationEffect(float duration, float scale, float x, float y, Entity layer) {
        final Sprite effectSkill = TilesPool.getEntityForTexture(ResourceManager.getInstance().getEffectSkill());
        effectSkill.setPosition(x, y);
        effectSkill.setAlpha(0f);
        effectSkill.setScale(scale);
        layer.attachChild(effectSkill);
        effectSkill.registerEntityModifier(getEffectStarRotationModifier(effectSkill, duration, scale));
    }

    private static IEntityModifier getEffectStarRotationModifier(final Sprite effectSkill, float durationModifier, float scale) {
        return new ParallelEntityModifier(
                new RotationModifier(DURATION_ROTATE_STAR_ON_ACTIVATE * durationModifier, 0, -180),
                new SequenceEntityModifier(
                        new AlphaModifier(DURATION_ROTATE_STAR_ON_ACTIVATE * durationModifier / 4, 0f, 1),
                        new AlphaModifier(DURATION_ROTATE_STAR_ON_ACTIVATE * durationModifier * 3 / 4, 1, 0f)
                ),
                new SequenceEntityModifier(
                        new ScaleAtModifier(DURATION_ROTATE_STAR_ON_ACTIVATE * durationModifier / 2, 0.5f * scale, 2 * scale, 0.5f, 0.5f),
                        new ScaleAtModifier(DURATION_ROTATE_STAR_ON_ACTIVATE * durationModifier / 2, 2 * scale, 0.5f * scale, 0.5f, 0.5f, new IEntityModifier.IEntityModifierListener() {
                            @Override
                            public void onModifierStarted(IModifier<IEntity> pModifier, IEntity pItem) {
                                //To change body of implemented methods use File | Settings | File Templates.
                            }

                            @Override
                            public void onModifierFinished(IModifier<IEntity> pModifier, IEntity pItem) {
                                MainBoardScreen.getInstanceEngine().runOnUpdateThread(new Runnable() {
                                    @Override
                                    public void run() {
                                        effectSkill.detachSelf();
                                        TilesPool.pushEntityToStack(effectSkill);
                                    }
                                });
                            }
                        })
                )
        );
    }


}
